const path = require('path');
const webpack = require('webpack');
const WebpackOnBuildPlugin = require('on-build-webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const WebpackPwaManifest = require('darmody-webpack-pwa-manifest');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const handleRouter = require('./webpack/handleRouter'); // 处理打包结果生成路由文件
const getEntriesRouter = require('./webpack/getEntriesRouter'); // 获取文件入口与路由
const notify = require('./webpack/notify'); // 打包消息通知
const cssModulesConfig = require('./webpack/cssModulesConfig');
const { execute } = require('./webpack/buildHook');
const webpackAlias = require('./webpack/webpack.alias');

require('colors'); // 终端输出color font

const vendorModulesRegex = new RegExp(
    `node_modules\\/(${[
        'history',
        'react',
        'react-dom',
        'prop-types',
        'classnames',
        'immutability-helper',
        'wpt-design',
        'tva',
    ].join('|')})`
);

const packageDir = path.join(__dirname, './packages');

process.env.PLATFORM = 'web';

// 获取配置
const CONFIG = (() => {
    function env(...args) {
        return args.includes(process.env.NODE_ENV);
    }

    return {
        srcPath: './src',
        env: process.env.NODE_ENV,
        sourceMap: process.env.SOURCE_MAP || '', // 是否使用sourceMap
        // 只有生产环境且生成source-map的时候，不删除dist
        rmDist: !(env('production') && process.env.SOURCE_MAP),
        uglifyJs: env('production'), // 压缩
        isProductionGray: env('production'), // 生成router-gray
        isDev: env('dev'), // 是否是开发环境
        isLocal: !!process.env.LOCAL, // 是否本地开发
        isAnalyze: env('analyze'), // 是否是开发环境
        distPath: '/dist',
        baseUrl: __dirname,
        actPack: !!process.env.ACT_PACK,
        gray: !!process.env.GRAY,
    };
})();

CONFIG.isDev &&
    console.log(
        `本地打包得到的文件大小并不是真实文件大小，因为其中包含了source-map
如果想获取真实未压缩大小可执行npm run online-pack，目前只在本地开发时开启source-map
ps: 本地开发使用inline-source-map`.green
    );
console.log(JSON.stringify(CONFIG, null, 4));

// 获取entries 与router
const { entries } = getEntriesRouter(CONFIG);

const filename = CONFIG.isLocal ? '[name].[hash:9].js' : '[name].[chunkhash:9].js';

function getActConfig() {
    return {
        entry: {
            [process.env.ACT_ENTRY]: process.env.ACT_ENTRY_PATH, // 活动模板
        },
        externals: {
            wpt: 'window.WPT',
            react: 'window.React',
            'react-dom': 'window.ReactDOM',
        },
        optimization: {
            namedChunks: true,
            namedModules: true,
            splitChunks: {
                name: 'vendor',
                cacheGroups: {
                    vendor: {
                        chunks: 'initial',
                        name: 'vendor',
                        test: 'vendor',
                        enforce: true,
                    },
                },
            },
        },
    };
}

function applyLessLoad(cssModule) {
    return [
        { loader: require.resolve('style-loader') },
        {
            loader: require.resolve('css-loader'),
            options: cssModule
                ? {
                      modules: {
                          localIdentName: '[local]--[hash:base64:5]',
                      },
                  }
                : undefined,
        },
        {
            loader: require.resolve('postcss-loader'),
            options: {
                plugins: [
                    require('autoprefixer')({
                        overrideBrowserslist: ['last 4 versions', 'ie 9', 'android 4.4.4', 'ios 8'],
                    }),
                ],
            },
        },
        {
            loader: require.resolve('less-loader'),
            options: { modifyVars: true, javascriptEnabled: true },
        },
    ];
}

module.exports = {
    cache: true,

    watch: false,

    mode: CONFIG.isDev ? 'development' : 'production',

    entry: {
        ...entries,
    },

    output: {
        path: path.resolve(__dirname, `.${CONFIG.distPath}`),
        filename,
        chunkFilename: '[name].[chunkhash:9].js',
        crossOriginLoading: 'anonymous',
    },
    externals: {
        wpt: 'window.WPT',
    },
    resolve: {
        alias: webpackAlias,
        unsafeCache: true,
        extensions: ['.web.js', '.js'],
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true,
                        },
                    },
                ],
            },
            {
                oneOf: [
                    {
                        test: /\.less$/,
                        resourceQuery: /css_modules/,
                        use: applyLessLoad(true),
                    },
                    {
                        test: function matchLess(pathname) {
                            if (pathname.endsWith('.m.less')) {
                                return true;
                            }
                            if (!pathname.endsWith('.less')) {
                                return false;
                            }
                            const relavitePath = path.relative(process.cwd(), pathname);
                            return cssModulesConfig.some((n) => relavitePath.startsWith(n));
                        },
                        use: applyLessLoad(true),
                    },
                    {
                        test: /\.less$/,
                        use: applyLessLoad(),
                    },
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.svg|png|jpg|jpeg$/,
                use: ['url-loader'],
            },
            {
                test: /\.ttf$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[hash:9].ttf',
                        },
                    },
                ],
            },
        ],
    },
    target: 'web',
    context: __dirname,
    devtool: CONFIG.sourceMap, // 使用sourceMap
    optimization: {
        namedChunks: true,
        namedModules: true,
        splitChunks: {
            name: 'vendor',
            cacheGroups: {
                vendor: {
                    minSize: 0,
                    chunks: 'initial',
                    name: 'vendor',
                    enforce: true,
                    test(module) {
                        const userRequest = module.userRequest;
                        if (!userRequest) return false;
                        return vendorModulesRegex.test(userRequest) || userRequest.startsWith(packageDir);
                    },
                },
            },
        },
        runtimeChunk: {
            name: 'manifest',
        },
        ...(CONFIG.gray && {
            minimize: true,
            minimizer: [
                new TerserPlugin({
                    terserOptions: {
                        mangle: {
                            keep_classnames: true,
                            keep_fnames: true,
                        },
                    },
                }),
            ],
        }),
    },

    ...(CONFIG.actPack && getActConfig()),
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, './local.html'),
            chunks: []
        }),
        new webpack.DefinePlugin({
            'process.env.PLATFORM': JSON.stringify('web'),
        }),
        new CaseSensitivePathsPlugin(), // 对于文件名，mac上默认不敏感、linux敏感，这里敏感
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
        }),
        // 开发环境 打包前清空
        CONFIG.rmDist && new CleanWebpackPlugin(path.resolve(__dirname, `.${CONFIG.distPath}`)),
        CONFIG.isAnalyze && new BundleAnalyzerPlugin(),
        CONFIG.isLocal && new webpack.EnvironmentPlugin(['LOCAL']),
        CONFIG.isLocal && new webpack.HotModuleReplacementPlugin(),
        // 打包结束
        new WebpackOnBuildPlugin((stats) => {
            const { compilation } = stats;
            const { errors } = compilation;

            handleRouter(compilation, CONFIG, {});
            if (errors.length > 0) {
                const error = errors[0];
                notify(error.name, error.message, true);
            } else {
                const warningNumber = compilation.warnings.length;
                let message = `takes ${stats.endTime - stats.startTime} ms`;
                if (warningNumber > 0) {
                    message += `,with ${warningNumber} warning(s)`;
                }

                notify('webpack building done', message);
            }

            execute();
        }),
        !CONFIG.actPack &&
            new WebpackPwaManifest({
                name: '金榜见',
                short_name: '金榜见',
                description: '金榜见',
                background_color: '#169BD9',
                theme_color: '#169BD9',
                display: 'standalone',
                start_url: 'https://m.yingzhibowangluokeji.com/',
                fingerprints: true,
                icons: [
                    {
                        src: path.resolve(__dirname, './images/logo.png'),
                        sizes: [96, 128, 192, 256, 384, 512], // multiple sizes
                    },
                ],
            }),
    ].filter((i) => i),
};
